package org.zjx.core;

import lombok.Data;
import org.zjx.factory.RouteFactory;
import org.zjx.model.route.Route;
import org.zjx.pojo.RouteQueryPojo;

import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;

/**
 * 路由缓存管理系统
 * 采用多级缓存策略：
 * 1. 静态路由图缓存（长期有效）
 * 2. 玩家路由图缓存（定时清理）
 */
public class CacheManager {
    private final RouteGraph staticGraph;
    private final RouteManager routeManager;
    private final RouteFactory routeFactory;
    private final ScheduledExecutorService cleaner;

    // 增加玩家数据版本控制
    private final ConcurrentHashMap<String, PlayerCacheEntry> playerCache;

    /**
     */
    @Data
    private static class PlayerCacheEntry {
        private final RouteGraph graph;
        private final long version;

        public PlayerCacheEntry(RouteGraph graph, long version){
            this.graph = graph;
            this.version = version;
        }
    }

    // 缓存配置参数
    private static final int CLEAN_INTERVAL = 1; // 小时
    private static final int MAX_CACHE_SIZE = 1000;

    public CacheManager(RouteGraph staticGraph, RouteManager routeManager, RouteFactory routeFactory) {
        this.staticGraph = Objects.requireNonNull(staticGraph);
        this.playerCache = new ConcurrentHashMap<>();
        this.routeFactory = Objects.requireNonNull(routeFactory);
        this.cleaner = Executors.newSingleThreadScheduledExecutor();
        this.routeManager = Objects.requireNonNull(routeManager);
        scheduleCleanup();
    }

    /**
     * 获取玩家路由图（带缓存）
     * @param routeQueryPojo 玩家数据
     * @return 完整路由图
     */
    public RouteGraph getPlayerGraph(RouteQueryPojo routeQueryPojo) {
        String playerId = routeQueryPojo.getPlayerId();
        PlayerCacheEntry entry = playerCache.get(playerId);
        if (entry != null && entry.version == routeQueryPojo.getVersion()) {
            return entry.graph;
        }

        // 需要重建缓存
        synchronized (this) {
            // 双重检查
            entry = playerCache.get(playerId);
            if (entry != null && entry.version == routeQueryPojo.getVersion()) {
                return entry.graph;
            }

            RouteGraph newGraph = buildPlayerGraph(routeQueryPojo);
            playerCache.put(playerId, new PlayerCacheEntry(newGraph, routeQueryPojo.getVersion()));
            return newGraph;
        }
    }

    private RouteGraph buildPlayerGraph(RouteQueryPojo routeQueryPojo) {
        RouteGraph graph = new RouteGraph(staticGraph);

        // 添加玩家动态路由
        List<Route> dynamicRoutes = routeFactory.createPlayerRoutes(routeQueryPojo);
        graph.addAllRoutes(dynamicRoutes);

        // 确保所有动态路由的落地点有连接
        for (Route route : dynamicRoutes) {
            routeManager.connectSpecialLocations(graph, route.getEnd(), false);
        }

        return graph;
    }

    public synchronized void cleanPlayerCache(String playerId) {
        synchronized (this) {
            playerCache.remove(playerId);
        }
    }

    /**
     * 定时清理策略：
     * 1. 按LRU原则清理
     * 2. 每小时执行一次
     */
    private void scheduleCleanup() {
        cleaner.scheduleAtFixedRate(() -> {
            if (playerCache.size() > MAX_CACHE_SIZE) {
                playerCache.entrySet().stream()
                        .sorted(Map.Entry.comparingByValue(
                                (g1, g2) -> Integer.compare(g2.hashCode(), g1.hashCode())))
                        .limit(MAX_CACHE_SIZE / 2)
                        .forEach(entry -> playerCache.remove(entry.getKey()));
            }
        }, CLEAN_INTERVAL, CLEAN_INTERVAL, TimeUnit.HOURS);
    }

    public void shutdown() {
        cleaner.shutdownNow();
        playerCache.clear();
    }
}